package ru.tusur.asu.pnn.perceptron;

import static java.lang.Math.exp;
import static java.lang.Math.abs;
import static ru.tusur.asu.utils.MathUtils.clamp;

public interface ActivationFunction {
	
	public static final float STEEPNESS = 1.0f;
	
	ActivationFunction SIGMOID = new ActivationFunction() {
		
		@Override
		public float value(float x) {
			return 2.0f / (1.0f + (float)exp(-2.0f * x)) - 1.0f;			
		}
		
		@Override
		public float derivative(float x, float func) {
			func = clamp(func, -0.98f, 0.98f);
		    return STEEPNESS * (1.0f - (func * func));
		}
	};
	
	ActivationFunction GAUSS = new ActivationFunction() {
		
		@Override
		public float value(float x) {
			return (float)exp(-x * x) * 2.0f - 1.0f;
		}
		
		@Override
		public float derivative(float x, float func) {
			return -2.0f * x * (func + 1) * STEEPNESS * STEEPNESS;
		}
	};
	
	ActivationFunction ELLIOT = new ActivationFunction() {
		
		@Override
		public float value(float x) {
			return x / (abs(x) + 1.0f);
		}
		
		@Override
		public float derivative(float x, float funcValue) {
			x = clamp(x, -0.98f, 0.98f);
		    return STEEPNESS / ((1.0f + abs(x)) * (1.0f + abs(x)));
		}
	};
	
	float value(float x);
	float derivative(float x, float funcValue);	
}
